#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <dirent.h>
#include <sys/time.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <errno.h>

#include "data_type.h"
#include "cube.h"
#include "cube_define.h"
#include "cube_record.h"

#include "tpm2_pcr.h"

#include "tpm2_value.h"
#include "tpm2_global.h"
#include "tpm2_structure.h"
#include "tpm2_command.h"
#include "vtcm_alg.h"

#include "tpm2_pcr.h"

int proc_tpm2_PCR_Read(void * sub_proc, void * recv_msg);
int proc_tpm2_PCR_Extend(void * sub_proc,void * recv_msg);
int proc_tpm2_PCR_getRandom(void * sub_proc, void *recv_msg);
//static int proc_tpm2_pcrreset(sub_proc, recv_msg);

int tpm2_pcr_init(void * sub_proc,void * para)
{
    int i,j;

	PCR * s_pcrs;
    TPM2_CUBE_GLOBAL * tpm2_global_data;
	tpm2_global_data=proc_share_data_getpointer();
	if(tpm2_global_data==NULL)
		return -EINVAL;
    s_pcrs=&tpm2_global_data->s_pcrs;

	for(i=0;i<IMPLEMENTATION_PCR;i++)
	{
		Memset(s_pcrs[i].sm3_256Pcr,0,SM3_256_DIGEST_SIZE);	
	}
	ex_module_setpointer(sub_proc,s_pcrs);

    return 0;
}

int tpm2_pcr_start(void * sub_proc,void * para)
{
    int ret;
    int retval;
    void * recv_msg;
    void * context;
    int i;
    int type;
    int subtype;
    BYTE uuid[DIGEST_SIZE];

    printf("tpm2_pcr module start!\n");

    while(1)
    {
        usleep(time_val.tv_usec);
        ret=ex_module_recvmsg(sub_proc,&recv_msg);
        if(ret<0)
            continue;
        if(recv_msg==NULL)
            continue;

        type=message_get_type(recv_msg);
        subtype=message_get_subtype(recv_msg);

        if((type==TYPE(TPM2_IN))&&(subtype==SUBTYPE(TPM2_IN,PCR_Extend)))
        {
            proc_tpm2_PCR_Extend(sub_proc,recv_msg);
        }
        else if((type==TYPE(TPM2_IN))&&(subtype==SUBTYPE(TPM2_IN,PCR_Read)))
        {
            proc_tpm2_PCR_Read(sub_proc,recv_msg);
        }
        else if((type==TYPE(TPM2_IN))&&(subtype==SUBTYPE(TPM2_IN,GetRandom)))
        {
            proc_tpm2_GetRandom(sub_proc,recv_msg);
        }
    }

    return 0;
};


int proc_tpm2_GetRandom(void * sub_proc, void * recv_msg)
{
    printf("proc_tpm2_GetRandom : Start\n");
    int ret = 0;
    int i = 0;

    RECORD(TPM2_IN,GetRandom) * tpm2_in;
    RECORD(TPM2_OUT,GetRandom) * tpm2_out;
    ret = message_get_record(recv_msg, (void *)&tpm2_in, 0);
    if(ret < 0)
        return ret;
    if(tpm2_in == NULL)
        return -EINVAL;
    //output process
    void * command_template = memdb_get_template(TYPE_PAIR(TPM2_OUT,GetRandom));
    if(command_template == NULL)
    {
		return -EINVAL;
    }
    tpm2_out = Talloc(struct_size(command_template));
	if(tpm2_out==NULL)
		return -EINVAL;

    tpm2_out->tag = TPM_ST_NO_SESSIONS;
    tpm2_out->responseCode = 0;
  
    if(tpm2_in->bytesRequested > 512)
  	   tpm2_out->randomBytes.size=512;
    else	
  	   tpm2_out->randomBytes.size=tpm2_in->bytesRequested;

    tpm2_out->responseSize = sizeof(*tpm2_out)-sizeof(BYTE *)+tpm2_out->randomBytes.size;
    
    tpm2_out->randomBytes.buffer=Talloc0(tpm2_out->randomBytes.size);
    if(tpm2_out->randomBytes.buffer==NULL)
        return -ENOMEM;
    ret = RAND_bytes(tpm2_out->randomBytes.buffer,tpm2_out->randomBytes.size);

    void *send_msg = message_create(TYPE_PAIR(TPM2_OUT,GetRandom), recv_msg);
    if(send_msg == NULL)
        return -EINVAL;
    message_add_record(send_msg, tpm2_out);

    ret = ex_module_sendmsg(sub_proc, send_msg);
    return ret;
}

int proc_tpm2_PCR_Extend(void * sub_proc,void * recv_msg)
{

    int ret=0;
    int i;
    printf("proc_tpm2_extend : Start \n") ;
    BYTE buffer[DIGEST_SIZE*2];
    PCR * s_pcrs;
    RECORD(TPM2_IN,PCR_Extend) * tpm2_in;
    RECORD(TPM2_OUT,PCR_Extend) * tpm2_out;
    int pcr_size;
    BYTE * pcr;
    void * send_msg;
    int tpm2_no; 
    int returnCode=0;
		
    s_pcrs = ex_module_getpointer(sub_proc);
    ret = message_get_record(recv_msg,(void **)&tpm2_in,0);
    if(ret<0)
        return ret;
    if(tpm2_in==NULL)
    {	
	returnCode=-EINVAL;
	goto extend_out_proc;
     }

    if((tpm2_in->pcrHandle<0)||(tpm2_in->pcrHandle>=IMPLEMENTATION_PCR))
    {	
	returnCode=-EINVAL;
	goto extend_out_proc;
    }

    pcr=s_pcrs[tpm2_in->pcrHandle].sm3_256Pcr;

    for(i=0;i<tpm2_in->digests.count;i++)
    {
	Memcpy(buffer,pcr,DIGEST_SIZE);
	vtcm_sm3(buffer+DIGEST_SIZE,1,tpm2_in->digests.digests[i].buffer,tpm2_in->digests.digests[i].size);	
    	vtcm_sm3(pcr,1,buffer, DIGEST_SIZE*2);
    }
    
extend_out_proc:
    tpm2_out=Talloc(sizeof(*tpm2_out));
    if(tpm2_out==NULL)
        return -ENOMEM;
    tpm2_out->tag = TPM_ST_NO_SESSIONS;
    tpm2_out->responseSize = sizeof(tpm2_out);
    tpm2_out->responseCode = returnCode;

    send_msg=message_create(TYPE_PAIR(TPM2_OUT,PCR_Extend),recv_msg);
    if(send_msg==NULL)
        return -EINVAL;

    message_add_record(send_msg,tpm2_out);
    ret=ex_module_sendmsg(sub_proc,send_msg);

    return ret;
}

int proc_tpm2_PCR_Read(void * sub_proc,void * recv_msg)
{
    int ret=0;
    int i;
    printf("proc_tpm2_pcrread : Start \n") ;
    BYTE buffer[DIGEST_SIZE*2];
    PCR * s_pcrs;
    RECORD(TPM2_IN,PCR_Read) * tpm2_in;
    RECORD(TPM2_OUT,PCR_Read) * tpm2_out;
    int pcr_size;
    BYTE * pcr;
    void * send_msg;
    int tpm2_no; 
    int returnCode=0;
		
    s_pcrs = ex_module_getpointer(sub_proc);
    ret = message_get_record(recv_msg,(void **)&tpm2_in,0);
    if(ret<0)
        return ret;
    if(tpm2_in==NULL)
    {	
	returnCode=-EINVAL;
	goto pcr_read_out_proc;
     }

/*
    if((tpm2_in->pcrHandle<0)||(tpm2_in->pcrHandle>=IMPLEMENTATION_PCR))
    {	
	returnCode=-EINVAL;
	goto extend_out_proc;
    }

    pcr=s_pcrs[tpm2_in->pcrHandle].sm3_256Pcr;

    for(i=0;i<tpm2_in->digests.count;i++)
    {
	Memcpy(buffer,pcr,DIGEST_SIZE);
	vtcm_sm3(buffer+DIGEST_SIZE,tpm2_in->digests.digests[i].buffer,tpm2_in->digests.digests[i].size);	
    	vtcm_sm3(pcr, buffer, pcr_size*2);
    }
*/    
pcr_read_out_proc:
    tpm2_out=Talloc(sizeof(*tpm2_out));
    if(tpm2_out==NULL)
        return -ENOMEM;
    tpm2_out->tag = TPM_ST_NO_SESSIONS;
    tpm2_out->responseSize = sizeof(tpm2_out);
    tpm2_out->responseCode = returnCode;

    send_msg=message_create(TYPE_PAIR(TPM2_OUT,PCR_Extend),recv_msg);
    if(send_msg==NULL)
        return -EINVAL;

    message_add_record(send_msg,tpm2_out);
    ret=ex_module_sendmsg(sub_proc,send_msg);


    return ret;
}
